#include "../faad2/aacToPcm.h"

AacToPcm::AacToPcm(uint64_t maxParseSize)
    : _maxParseSize(maxParseSize), _lastAacPos(0), _aac2pcmInitFlag(false), _hDecoder(nullptr)
{
}

AacToPcm::~AacToPcm()
{
    if (_hDecoder)
    {
        NeAACDecClose(_hDecoder);
        _hDecoder = nullptr;
    }
}

int AacToPcm::init()
{
    _hDecoder = NeAACDecOpen();
    if (!_hDecoder)
    {
        return -1;
    }

    NeAACDecConfigurationPtr config = NeAACDecGetCurrentConfiguration(_hDecoder);
    config->defSampleRate = 16000;
    config->defObjectType = HE_AAC;
    config->outputFormat = FAAD_FMT_16BIT; // 位深度设置成16bit

    //    源码部分如下：
    //    if (*samplerate <= 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0))
    //    {
    //        *samplerate *= 2;
    //        hDecoder->forceUpSampling = 1;
    //    } else if (*samplerate > 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0)) {
    //        hDecoder->downSampledSBR = 1;
    //    }
    //    dontUpSampleImplicitSBR 设置成1，可以禁止NeAACDecInit时，采样率（小于等于24000时）翻倍的问题
    config->dontUpSampleImplicitSBR = 1;
    NeAACDecSetConfiguration(_hDecoder, config);

    return 0;
}

std::string AacToPcm::aacToPcm(const std::string &aacData)
{
    if (!_aac2pcmInitFlag)
    {
        unsigned long lSampleRate = 0;
        uint8_t nChannel = 0;
        if (-1 == NeAACDecInit(_hDecoder, (uint8_t *)aacData.data(), aacData.size(), &lSampleRate, &nChannel))
        {
            return "";
        }
        _aac2pcmInitFlag = true;
    }

    NeAACDecFrameInfo hInfo;
    char *pData = nullptr;
    pData = (char *)NeAACDecDecode(_hDecoder, &hInfo, (uint8_t *)aacData.data(), aacData.size());
    if (hInfo.error > 0 || !pData)
    {
        fprintf(stderr, "NeAACDecDecode error(%d)\r\n", hInfo.error);
        return "";
    }
    else
    {
        uint32_t dataSize = 1024 * hInfo.channels * 16 / 8; // 位深度是16bit (FAAD_FMT_16BIT)
        return std::string(pData, dataSize);
    }
}

int AacToPcm::inputAacData(uint8_t *data, uint32_t len)
{
    if (_lastAacPos > 0 && _lastAacPos < _aacData.size())
    {
        _aacData.erase(0, _lastAacPos);
    }
    _lastAacPos = 0;

    // 如果数据量 < _maxParseSize, 则append
    // 反正则抛弃之前的数据
    if (len + _aacData.size() < _maxParseSize)
    {
        _aacData.append((const char *)data, len);
    }
    else if (len > _maxParseSize)
    {
        fprintf(stderr, "data Size(%d) is too large to contain\n", len);
    }
    else
    {
        _aacData = std::string((const char *)data, len);
    }
    if (splitAacData())
    {
        return -1;
    }

    for (const auto &aac : _aacSplitData)
    {
        std::string pcm = aacToPcm(aac);
        if (!pcm.empty())
        {
            _pcmQueue.push(std::move(pcm));
        }
    }
    return 0;
}

std::string AacToPcm::outputPcmData()
{
    if (_pcmQueue.empty())
    {
        return "";
    }
    std::string pcm = _pcmQueue.front();
    _pcmQueue.pop();
    return pcm;
}

int AacToPcm::splitAacData()
{
    _aacSplitData.clear();

    std::string::size_type rpos = _aacData.find(0xff, 0);
    _lastAacPos = -1;
    while (rpos != std::string::npos)
    {
        //        adts header 长度7
        if (rpos + 7 > _aacData.size())
        {
            _lastAacPos = rpos;
            break;
        }

        //        adts header 中 syncword：帧同步标识一个帧的开始，固定为0xFFF
        //        layer：固定为'00'
        uint8_t code = _aacData[rpos + 1];
        if (((code & (uint8_t)0xf0) != 0xf0) || (code & (uint8_t)0x06) != 0)
        {
            rpos = _aacData.find(0xff, rpos + 1);
            continue;
        }

        uint8_t i = _aacData[rpos + 3];
        uint8_t j = _aacData[rpos + 4];
        uint8_t k = _aacData[rpos + 5];
        uint32_t aacFrameLen = ((i & 0x3) << 9) + (j << 3) + ((k & 0xe0) >> 5);
        if (rpos + aacFrameLen > _aacData.size())
        {
            _lastAacPos = rpos;
            break;
        }
        else
        {
            _aacSplitData.push_back(_aacData.substr(rpos, aacFrameLen));

            // 最后一个分段正好是一个完整的aac帧
            if (rpos + aacFrameLen == _aacData.size())
            {
                _lastAacPos = -1;
                _aacData.clear();
                break;
            }
        }

        rpos = _aacData.find(0xff, rpos + aacFrameLen);
    }

    return _aacSplitData.empty() ? -1 : 0;
}
